﻿using System.Drawing;
using System.Windows.Forms;
using ArtMath.Core.Data;
using ArtMath.Core.Helper;
using System;
using ArtMath.Resource;
using ArtMath.Setting;

namespace ArtMath.AuxiliaryTool
{
    /// <summary>
    /// 自由变换
    /// </summary>
    public class Transform : ToolBase
    {
        public enum TransformType
        {
            MoveObject,
            SizeLT,
            SizeT,
            SizeRT,
            SizeR,
            SizeRB,
            SizeB,
            SizeLB,
            SizeL,
            Rotate,
            MoveRotateCenter,
        }
        const int POINT_SIZE = 8, DRAW_OFFSET = 4;
        RectangleD oldRect, newRect;
        PointD oldRotateCenter, newRotateCenter;
        double oldRotateAngle, newRotateAngle, dist, startAngle;
        TransformType currentType;
        public bool SupportNegativeSize { get; set; } = true;
        public bool ProportionLocked { get; set; } = false;
        bool raiseLocationChangedEvent;
        public event Action<Cursor> CursorChanged;
        public event Action<PointD> RotateCenterChanged, LocationChanged;
        public event Action<double> RotateAngleChanged;
        public Transform(RectangleD initRect, PointD initRotateCenter, double initRotateAngle)
        {
            oldRect = newRect = initRect;
            oldRotateCenter = newRotateCenter = initRotateCenter;
            oldRotateAngle = newRotateAngle = initRotateAngle;
        }
        public override void MouseDown(MouseEventArgs e)
        {
            switch (currentType)
            {
                case TransformType.Rotate:
                    dist = newRotateCenter.DistanceTo(newRect.Location);
                    startAngle = newRotateAngle;
                    CursorChanged?.Invoke(new Cursor(Resource.Properties.Resources.rotate_do.GetHicon()));
                    break;
            }
        }
        public override void MouseMove(MouseMoveEventArgs e)
        {
            switch (e.Button)
            {
                case MouseButtons.Left:
                    switch (currentType)
                    {
                        case TransformType.MoveObject:
                            newRect.Location += e.POffset;
                            raiseLocationChangedEvent = true;
                            break;
                        case TransformType.SizeLT:
                            break;
                        case TransformType.SizeT:
                            break;
                        case TransformType.SizeRT:
                            break;
                        case TransformType.SizeR:
                            break;
                        case TransformType.SizeRB:
                            break;
                        case TransformType.SizeB:
                            break;
                        case TransformType.SizeLB:
                            break;
                        case TransformType.SizeL:
                            break;
                        case TransformType.Rotate:
                            //int sign = Utility.IsClockwise(newRotateCenter, downCoordinate, e.CurrentPosition) ? 1 : -1;
                            //double angle = Utility.GetAngle(newRotateCenter, downCoordinate, e.CurrentPosition) * sign;
                            //newRotateAngle = startAngle + angle;
                            //newRect.Location = newRotateCenter.Offset(-newRotateAngle, dist);
                            raiseLocationChangedEvent = false;
                            break;
                        case TransformType.MoveRotateCenter:
                            newRotateCenter = e.CurrentPosition;
                            break;
                    }
                    if (Settings.Instance.RealTimeTransform)
                    {
                        Complete();
                    }
                    break;
                case MouseButtons.None:
                    if (e.CurrentPosition.DistanceTo(newRect.Location) <= Settings.Instance.PointAbsorb)
                    {
                        CursorChanged?.Invoke(Cursors.SizeNWSE);
                        currentType = TransformType.SizeLT;
                    }
                    else if (e.CurrentPosition.DistanceTo(newRect.BottomRight.RotateAt(newRect.Location, -newRotateAngle)) <= Settings.Instance.PointAbsorb)
                    {
                        CursorChanged?.Invoke(Cursors.SizeNWSE);
                        currentType = TransformType.SizeRB;
                    }
                    else if (e.CurrentPosition.DistanceTo(newRect.TopRight.RotateAt(newRect.Location, -newRotateAngle)) <= Settings.Instance.PointAbsorb)
                    {
                        CursorChanged?.Invoke(Cursors.SizeNESW);
                        currentType = TransformType.SizeRT;
                    }
                    else if (e.CurrentPosition.DistanceTo(newRect.BottomLeft.RotateAt(newRect.Location, -newRotateAngle)) <= Settings.Instance.PointAbsorb)
                    {
                        CursorChanged?.Invoke(Cursors.SizeNESW);
                        currentType = TransformType.SizeLB;
                    }
                    else if (e.CurrentPosition.DistanceTo(newRect.TopCenter.RotateAt(newRect.Location, -newRotateAngle)) <= Settings.Instance.PointAbsorb)
                    {
                        CursorChanged?.Invoke(Cursors.SizeNS);
                        currentType = TransformType.SizeT;
                    }
                    else if (e.CurrentPosition.DistanceTo(newRect.BottomCenter.RotateAt(newRect.Location, -newRotateAngle)) <= Settings.Instance.PointAbsorb)
                    {
                        CursorChanged?.Invoke(Cursors.SizeNS);
                        currentType = TransformType.SizeB;
                    }
                    else if (e.CurrentPosition.DistanceTo(newRect.MiddleRight.RotateAt(newRect.Location, -newRotateAngle)) <= Settings.Instance.PointAbsorb)
                    {
                        CursorChanged?.Invoke(Cursors.SizeWE);
                        currentType = TransformType.SizeR;
                    }
                    else if (e.CurrentPosition.DistanceTo(newRect.MiddleLeft.RotateAt(newRect.Location, -newRotateAngle)) <= Settings.Instance.PointAbsorb)
                    {
                        CursorChanged?.Invoke(Cursors.SizeWE);
                        currentType = TransformType.SizeL;
                    }
                    else if (e.CurrentPosition.DistanceTo(newRotateCenter) <= Settings.Instance.PointAbsorb)
                    {
                        CursorChanged?.Invoke(Cursors.SizeAll);
                        currentType = TransformType.MoveRotateCenter;
                    }
                    else if (newRect.Contains(e.CurrentPosition.RotateAt(newRect.Location, newRotateAngle)))
                    {
                        CursorChanged?.Invoke(Cursors.SizeAll);
                        currentType = TransformType.MoveObject;
                    }
                    else
                    {
                        CursorChanged?.Invoke(new Cursor(Resource.Properties.Resources.rotate_prepare.GetHicon()));
                        currentType = TransformType.Rotate;
                    }
                    break;
            }
        }
        public override void MouseUp(MouseEventArgs e)
        {
            switch (currentType)
            {
                case TransformType.Rotate:
                    CursorChanged?.Invoke(new Cursor(Resource.Properties.Resources.rotate_prepare.GetHicon()));
                    break;
            }
        }
        //public void ChangeSize(SizeD delta)
        //{
        //    switch (mode)
        //    {
        //        case MoveMode.moveAll:
        //            rect.Left += delta.Width;
        //            rect.Top += delta.Height;
        //            break;
        //        case MoveMode.sizeRB:
        //            rect.Width += delta.Width;
        //            rect.Height += delta.Height;
        //            break;
        //        case MoveMode.sizeLT:
        //            rect.Width -= delta.Width;
        //            rect.Height -= delta.Height;
        //            rect.Left += delta.Width;
        //            rect.Top += delta.Height;
        //            break;
        //    }
        //}
        public override void Complete()
        {
            if (raiseLocationChangedEvent && newRect.Location != oldRect.Location)
            {
                LocationChanged?.Invoke(newRect.Location);
            }
            if (newRotateCenter != oldRotateCenter)
            {
                RotateCenterChanged?.Invoke(newRotateCenter);
            }
            if (newRotateAngle != oldRotateAngle)
            {
                RotateAngleChanged?.Invoke(newRotateAngle);
            }
        }
        public void DiscardChanges()
        {
            if (Settings.Instance.RealTimeTransform)
            {
                LocationChanged?.Invoke(oldRect.Location);
                RotateCenterChanged?.Invoke(oldRotateCenter);
                RotateAngleChanged?.Invoke(oldRotateAngle);
            }
        }
        public override void Paint(Graphics gra)
        {
            if (!Settings.Instance.RealTimeTransform)
            {

            }
            gra.Transform(newRect.Location, -newRotateAngle * Angle.RToD, () =>
            {
                gra.DrawRectangle(new Pen(Color.FromArgb(102, 204, 255), 1), 0, 0, (float)newRect.Width, (float)newRect.Height);
                gra.DrawImage(Resource.Properties.Resources.movePoint, -DRAW_OFFSET, -DRAW_OFFSET, POINT_SIZE, POINT_SIZE);
                gra.DrawImage(Resource.Properties.Resources.movePoint, -DRAW_OFFSET, (float)(newRect.Height / 2 - DRAW_OFFSET), POINT_SIZE, POINT_SIZE);
                gra.DrawImage(Resource.Properties.Resources.movePoint, -DRAW_OFFSET, (float)(newRect.Height - DRAW_OFFSET), POINT_SIZE, POINT_SIZE);
                gra.DrawImage(Resource.Properties.Resources.movePoint, (float)(newRect.Width / 2 - DRAW_OFFSET), (float)(newRect.Height - DRAW_OFFSET), POINT_SIZE, POINT_SIZE);
                gra.DrawImage(Resource.Properties.Resources.movePoint, (float)(newRect.Width - DRAW_OFFSET), (float)(newRect.Height - DRAW_OFFSET), POINT_SIZE, POINT_SIZE);
                gra.DrawImage(Resource.Properties.Resources.movePoint, (float)(newRect.Width - DRAW_OFFSET), (float)(newRect.Height / 2 - DRAW_OFFSET), POINT_SIZE, POINT_SIZE);
                gra.DrawImage(Resource.Properties.Resources.movePoint, (float)(newRect.Width - DRAW_OFFSET), -DRAW_OFFSET, POINT_SIZE, POINT_SIZE);
                gra.DrawImage(Resource.Properties.Resources.movePoint, (float)(newRect.Width / 2 - DRAW_OFFSET), -DRAW_OFFSET, POINT_SIZE, POINT_SIZE);
            });
            Size sz = Resource.Properties.Resources.target.Size;
            gra.DrawImage(Resource.Properties.Resources.target, (float)(newRotateCenter.X - sz.Width / 2), (float)(newRotateCenter.Y - sz.Height / 2), sz.Width, sz.Height);
        }
    }
}
